﻿#include "graphicsscene.h"

#include <QGraphicsBlurEffect>
#include <QGraphicsView>
#include <QMediaPlayer>
#include <QInputDialog>

#include "block.h"
#include "blockgroup.h"
#include "blockgroupmove.h"

GraphicsScene::GraphicsScene(QObject *parent) : QGraphicsScene(parent)
{
    scene_init();

    // 初始化标准计时器
    stand_timer = new QTimer(this);
    stand_timer->setInterval(100);
    game_time.setHMS(0, 0, 0);
    connect(stand_timer, &QTimer::timeout, [this] {
        // game_time = game_time.addSecs(1);
        game_time = game_time.addMSecs(100);
        time_item->setPlainText(game_time.toString("hh:mm:ss.z"));
        fresh_time_on_record();
    });

    nextBlockGroup = new BlockGroup(QPointF(520, 120) );
    addItem(nextBlockGroup);

    currentBlockGroup = new BlockGroupMove(QPointF(220, 30));
    addItem(currentBlockGroup);

    connect(currentBlockGroup, &BlockGroupMove::need_next_shape, this, [this]{
        this->clear_full_rows();
        currentBlockGroup->copyShape(nextBlockGroup);
        nextBlockGroup->newShape();
    });
    connect(currentBlockGroup, &BlockGroupMove::clear_full_rows, this, &GraphicsScene::clear_full_rows);
    connect(currentBlockGroup, &BlockGroupMove::game_over, this, [this]{
        this->slot_game_over();
    });
    connect(currentBlockGroup, &BlockGroupMove::game_over, this, &GraphicsScene::gameOver);     //信号中继

    // 统计信息初始化
    statistics_reload();
}

/**
 * @brief   游戏开始
 */
void GraphicsScene::game_start()
{
    // 清除场景内已有的方块
    clearAllBlocks();

    //分数清零
    score = 0;
    game_time.setHMS(0, 0, 0);

    // 计时器开始
    stand_timer->start();
    is_game_pause = false;

    //初始化统计栏
    statistics_reset();
    game_pause(false);

    //音乐开始
    ST->setBackgroundMusicEnable(true);

    // 方块组开始行动
    nextBlockGroup->newShape();
    currentBlockGroup->game_start();
}

/**
 * @brief   游戏暂停/继续
 */
void GraphicsScene::game_pause(bool flag)
{
    currentBlockGroup->game_pause(flag);
    if (flag) {
        stand_timer->stop();
        is_game_pause = true;
        status_item->setPlainText("Pause");
        status_item->setDefaultTextColor(Qt::red);
        ST->setBackgroundMusicEnable(false);
    } else {
        stand_timer->start();
        is_game_pause = false;
        status_item->setPlainText("Playing");
        status_item->setDefaultTextColor(Qt::green);
        ST->setBackgroundMusicEnable(true);
    }
}

/**
 * @brief   设置玩家姓名
 */
void GraphicsScene::set_player(const QString &name)
{
    player_item->setPlainText(name);
}

/*
 * @Brief:  清除满行
 * @Detail: 做了个动画效果
 */
void GraphicsScene::clear_full_rows()
{
    QList<int> full_row_list;                   //记录满行的行号

    for (int i = 0; i < 20; ++i) {
//        auto item_list = this->items(0, 10 + i * 40, 400, 40, Qt::ContainsItemShape, Qt::AscendingOrder);
        auto item_list = this->items(-1, 10 + i * 40 -1 , 402, 42, Qt::ContainsItemShape, Qt::AscendingOrder);

        if (item_list.count() >= 10) {
            //必须是
            foreach (auto item, item_list) {
                if (item->type() != NormalBlock && item->type() != PassModeBlock) {
                    continue;
                }
            }

            // 遍历列表删除小方块
            foreach (auto item, item_list) {
                // 模糊效果，先放大再缩小
                Block *block = static_cast<Block *>(item);
                QGraphicsBlurEffect *blurEffect = new QGraphicsBlurEffect;
                block->setGraphicsEffect(blurEffect);
                QPropertyAnimation *animation = new QPropertyAnimation(block, "scale");
                animation->setDuration(250);
                animation->setEasingCurve(QEasingCurve::OutBounce);
                animation->setStartValue(4);
                animation->setEndValue(0.25);
                animation->start(QAbstractAnimation::DeleteWhenStopped);
                connect(animation, &QPropertyAnimation::finished, block, &Block::deleteLater);
            }
            // 记录满行的行地址
            full_row_list.append(i);
        }
    }
//    qDebug()<<"满行检查结果："<<full_row_list;

    if(!full_row_list.isEmpty()) {
        // QSound::play(":/audio/remove.wav");
        ST->soundList()->remove.play();
        currentBlockGroup->setKeyPressEventEnable(false);
        //等待所有的小正方形都销毁后再将上方的小正方形向下移动
        ST->delay_ms(300);
        for (int i = 0; i < full_row_list.count(); ++i) {
//                auto item_list = this->items(0, 10, 400, full_row_list.at(i)*40, Qt::ContainsItemShape, Qt::AscendingOrder);
            auto item_list = this->items(-1, 9, 402, full_row_list.at(i)*40 + 1, Qt::ContainsItemShape, Qt::AscendingOrder);
            foreach (auto item, item_list) {
                item->moveBy(0, 40);
            }
        }
        // 更新分数
        updateScore(full_row_list.count());
        currentBlockGroup->setKeyPressEventEnable(true);
    }
}

/**
 * @brief   游戏结束的场景响应函数
 * @details
 * @param   isPassed - 是否通关成功，关系到显示文字
 */
void GraphicsScene::slot_game_over(bool isPassed)
{
    stand_timer->stop();
    is_game_pause = true;
    ST->setBackgroundMusicEnable(false);
    if (isPassed) {
        status_item->setPlainText("Game Passed");
        status_item->setDefaultTextColor(Qt::green);
    } else {
        status_item->setPlainText("Game Over");
        status_item->setDefaultTextColor(Qt::red);
    }
    currentBlockGroup->game_end();
    switch (ST->settings()->value("GameMode", 1).toInt()) {
    case StandardMode:
        if (ST->canRankInStandardRecord(score)) {
            bool ok;
            QString text = QInputDialog::getText((QWidget *)this->views().first()->parent(), tr("标准模式记录"),
                                                 tr("您的分数已经跻身十强，请输入大名"), QLineEdit::Normal,
                                                 QDir::home().dirName(), &ok);
            if (ok && !text.isEmpty()) {
                Record r;
                r.name = text;
                r.score = score;
                r.play_time = game_time;
                r.record_time = QDateTime::currentDateTime();
                ST->insertStandardModeRecord(r);
                emit showRank(StandardMode);        //显示得分榜
            }
        }
        break;
    case PassMode:{
        Record r;
        r.score = score;
        r.pass_difficulty = m_pass_difficulty;
        r.play_time = game_time;
        r.record_time = QDateTime::currentDateTime();
        if (ST->canRankInPassRecord(r)) {
            bool ok;
            QString text = QInputDialog::getText((QWidget *)this->views().first()->parent(), tr("闯关模式记录"),
                                                 tr("您的分数已经跻身十强，请输入大名"), QLineEdit::Normal,
                                                 QDir::home().dirName(), &ok);
            if (ok && !text.isEmpty()) {
                r.name = text;
                r.time_pass0 = pass_time_list[0];
                r.time_pass1 = pass_time_list[1];
                r.time_pass2 = pass_time_list[2];
                r.time_pass3 = pass_time_list[3];
                r.time_pass4 = pass_time_list[4];
                r.time_pass5 = pass_time_list[5];
                r.time_pass6 = pass_time_list[6];
                r.time_pass7 = pass_time_list[7];
                r.time_pass8 = pass_time_list[8];
                r.time_pass9 = pass_time_list[9];
                ST->insertPassModeRecord(r);
                statistics_reload();
                emit showRank(PassMode);        //显示得分榜
            }
        }
    }
        break;
    default:
        break;
    }
}

/**
 * @brief   绘制前景
 * @details 用于遮挡超出游戏框体的游戏区域
 */
void GraphicsScene::drawForeground(QPainter *painter, const QRectF &rect)
{
    Q_UNUSED(rect)

    // 绘制上部背景
    painter->setBrush(QBrush("#444693"));
    painter->setPen(QPen(Qt::NoPen));
    painter->drawRect(-20, -100, 440, 80);

    // 绘制上方条框
    painter->setBrush(QBrush("#2a5caa"));
    painter->drawRect(-20, -20, 440, 20);
}

/*
 * @Brief:  绘制背景
 */
void GraphicsScene::drawBackground(QPainter *painter, const QRectF &rect)
{
    // 绘制背景
    painter->setBrush(QBrush("#444693"));
    painter->setPen(QPen(Qt::NoPen));
    painter->drawRect(rect);

    // 外框
    painter->setBrush(QBrush("#2a5caa"));
    painter->drawRect(-20, -20, 440, 850);

    // 内框
    painter->setBrush(QBrush("#1a2933"));
    painter->drawRect(0, 0, 400, 810);

    // 网格线
    painter->setPen(QPen("#102b6a"));
    for (int i = 0; i < 20; ++i) {
        painter->drawLine(0, 10 + i * 40, 400, 10 + i * 40);
    }
    for (int i = 0; i < 10; ++i) {
        painter->drawLine(i * 40, 0, i * 40, 810);
    }

    // 技术统计栏
    painter->setPen(QPen(Qt::NoPen));
    painter->setBrush(QBrush("#2a5caa"));
    painter->drawRect(-240, -20, 200, 250);

    // 下一个方块
    painter->drawRect(440, -20, 200, 250);

    //提示信息
    painter->drawRect(-240, 650, 200, 180);
}

/**
 * @brief   初始化场景的一些部件
 * @details
 */
void GraphicsScene::scene_init()
{
    // 虚拟框（检测碰撞用）
    this->addRect(0, 811, 400, 40, QPen(Qt::NoPen));    // 底部条
    this->addRect(-41, 0, 40, 810, QPen(Qt::NoPen));    // 左侧条
    this->addRect(401, 0, 40, 810, QPen(Qt::NoPen));    // 右侧条

    // 技术统计栏
    QFont font_title("Calibri", 10, QFont::Bold);
    QFont font_sub("Calibri", 15);
    QFont font_big("Calibri", 23, QFont::Bold);

    set_text("Player", QPointF(-230, -20), font_title);
    player_item = set_text(ST->settings()->value("PlayerName", QDir::home().dirName()).toString(), QPointF(-230, 0), font_sub);

    set_text("Time", QPointF(-230, 30), font_title);
    time_item = set_text("00:00:00", QPointF(-230, 50), font_sub);

    set_text("Score", QPointF(-230, 80), font_title);
    score_item = set_text("0", QPointF(-230, 100), font_sub);

    set_text("Speed", QPointF(-230, 130), font_title);
    speed_item = set_text("1", QPointF(-230, 150), font_sub);

    // 状态文字
    status_item = set_text("Playing", QPointF(-230, 185), font_sub, Qt::green);

    // 下一个方块
    set_text("Next", QPointF(450, -20), font_sub);

    pass_item = set_text("", QPointF(-230, 660), font_sub);
    tip_item = set_text("", QPointF(-230, 720), font_big, Qt::green);

    //通关时间列表
    QFont font_record("Calibri", 12);
    pass_time_text_current_title = set_text(tr("当前"), QPointF(550, 440), font_record);
    pass_time_text_record_title = set_text(tr("记录"), QPointF(666, 440), font_record);
    for (int i = 0; i < 9; ++i) {
        pass_time_text_list << set_text(tr("关卡%1").arg(i+1), QPointF(450, 480 + i * 40), font_record);
        pass_time_text_current_list << set_text("    -", QPointF(520, 480 + i * 40), font_record);
        pass_time_text_record_list << set_text("    -", QPointF(653, 480 + i * 40), font_record);
    }

    this->setSceneRect(-250, -50, 900, 900);
}

/**
 * @brief   记录加载
 */
void GraphicsScene::statistics_reload()
{
    pass_time_list.clear();
    pass_time_record_list.clear();
    pass_time_list << QTime(-1, 0, 0) << QTime(-1, 0, 0) << QTime(-1, 0, 0) << QTime(-1, 0, 0) << QTime(-1, 0, 0)
                   << QTime(-1, 0, 0) << QTime(-1, 0, 0) << QTime(-1, 0, 0) << QTime(-1, 0, 0) << QTime(-1, 0, 0);

    if (ST->pass_record_list().isEmpty()) {
        pass_time_record_list = pass_time_list;
    } else {
        auto r = ST->pass_record_list().first();
        pass_time_record_list << r.time_pass0 << r.time_pass1 << r.time_pass2 << r.time_pass3 << r.time_pass4
                              << r.time_pass5 << r.time_pass6 << r.time_pass7 << r.time_pass8 << r.time_pass9;
    }
}

/**
 * @brief   当前记录重置
 * @details 记录刷新，颜色也要重置
 */
void GraphicsScene::statistics_reset()
{
    for (int i = 0; i < 9; ++i) {
        pass_time_text_current_list[i]->setDefaultTextColor(Qt::white);
        pass_time_text_current_list[i]->setPlainText("         -");
        auto t_r = pass_time_record_list[i];
        if (t_r.isValid()) {
            // pass_time_text_record_list[i]->setPlainText(pass_time_record_list[i].toString("hh:mm:ss"));
            pass_time_text_record_list[i]->setPlainText(pass_time_record_list[i].toString("mm:ss.z"));
        } else {
            pass_time_text_record_list[i]->setPlainText("      -");
        }
    }

    if (ST->settings()->value("GameMode", 1).toInt() == PassMode) {
        set_pass_difficulty(1);
        if (ST->settings()->value("ShowRecord", true).toBool()) {
            set_statistics_visible(true);
        } else {
            set_statistics_visible(false);
        }
    } else {
        set_statistics_visible(false);
    }
}

/**
 * @brief   设置记录栏是否隐藏
 * @details 记录栏只有在闯关模式显示
 * @param   visible - 是否隐藏
 */
void GraphicsScene::set_statistics_visible(bool visible)
{
    if (visible) {
        pass_time_text_current_title->show();
        pass_time_text_record_title->show();
        for (int i = 0; i < 9; ++i) {
            pass_time_text_list[i]->show();
            pass_time_text_current_list[i]->show();
            pass_time_text_record_list[i]->show();
        }
    } else {
        pass_time_text_current_title->hide();
        pass_time_text_record_title->hide();
        for (int i = 0; i < 9; ++i) {
            pass_time_text_list[i]->hide();
            pass_time_text_current_list[i]->hide();
            pass_time_text_record_list[i]->hide();
        }
    }
}

QGraphicsTextItem *GraphicsScene::set_text(QString text, QPointF pos, QFont font, QColor color)
{
    QGraphicsTextItem *item = this->addText(text, font);
    item->setPos(pos);
    item->setDefaultTextColor(color);
    return item;
}

/**
 * @brief   更新分数
 * @details
 * @param   row_count -- 消除行数
 */
void GraphicsScene::updateScore(int row_count)
{
    int add_score = 0;
    switch (row_count) {
    case 1:
        add_score = 1;
        break;
    case 2:
        add_score = 3;
        break;
    case 3:
        add_score = 6;
        break;
    case 4:
        add_score = 10;
        break;
    default:
        break;
    }

    ST->delay_ms(100);

    score_item->setPlainText(QString("%1 + %2").arg(score).arg(add_score));
    score_item->setDefaultTextColor(Qt::green);
    score += add_score;
    // 这里进行难度增加或者关卡通过判断
    switch (ST->settings()->value("GameMode", 1).toInt()) {
    case StandardMode:
        // 增加速度
        if (ST->settings()->value("SpeedOn", true).toBool()) {
            int speed = qMin(1 + score / 10, 15);   //最高为15速
            if (speed != currentBlockGroup->speed()) {
                speed_item->setPlainText(QString::number(speed));
                currentBlockGroup->setSpeed(speed);
            }
        }
        break;
    case PassMode:{
        auto item_list = allBlocks();
        bool flag = false;      //过关标志
        foreach (auto item, item_list) {
            Block *block = static_cast<Block *>(item);
            if ((BlockType)block->type() == PassModeBlock) {
                flag = true;
                break;
            }
        }
        if (flag == false) {    // 闯关成功
            ST->soundList()->success.play();

            pass_time_list[m_pass_difficulty-1] = game_time;      //记录通小关的游戏时间

            auto *animation = new QVariantAnimation(this);      //闯关时间固化后的动画效果
            animation->setDuration(250);
            animation->setEasingCurve(QEasingCurve::OutCubic);
            animation->setStartValue(12.0);
            animation->setKeyValueAt(0.85, 15.0);
            animation->setEndValue(12.0);
            animation->start(QAbstractAnimation::DeleteWhenStopped);
            auto current_text = pass_time_text_current_list[m_pass_difficulty-1];
            connect(animation, &QVariantAnimation::valueChanged, this, [current_text](const QVariant &value){
                auto font = current_text->font();
                font.setPointSizeF(value.toReal());
                current_text->setFont(font);
            });
            connect(animation, &QVariantAnimation::finished, this, [current_text]{
                auto font = current_text->font();
                font.setBold(false);
                current_text->setFont(font);
            });

            stand_timer->stop();        //过关时暂停游戏时钟
            if (m_pass_difficulty >= 9) {    // 闯关成功，游戏结束
                tip_item->setPlainText("恭喜通关！");
                currentBlockGroup->game_end();
                clearAllBlocks();
                m_pass_difficulty = 10;
                slot_game_over(true);
                currentBlockGroup->hide();      //隐藏移动块
            } else {    // 进入下一关
                tip_item->setPlainText("闯关成功");
                QTimer::singleShot(1500, this, [this] {
                    tip_item->setPlainText("");
                });
                ST->delay_ms(700);
                clearAllBlocks();
                set_pass_difficulty(m_pass_difficulty + 1);
                if (!is_game_pause) {
                    qDebug()<<"恢复主计时器";
                    stand_timer->start();       //恢复暂停的游戏时钟
                }
                currentBlockGroup->copyShape(nextBlockGroup);
                nextBlockGroup->newShape();
            }
        }
    }
        break;
    default:
        break;
    }
    QTimer::singleShot(1000, this, [this]{
        score_item->setPlainText(QString::number(score));
        score_item->setDefaultTextColor(Qt::white);
    });
}

QList<QGraphicsItem *> GraphicsScene::allBlocks()
{
    return this->items(-1, -80, 402, 892, Qt::ContainsItemShape, Qt::AscendingOrder);
}

void GraphicsScene::clearAllBlocks()
{
    foreach (auto item, allBlocks()) {
        Block *block = static_cast<Block *>(item);
        this->removeItem(block);
        block->deleteLater();
    }
}

/**
 * @brief   以一定难度初始化游戏
 * @details
 * @param   difficulty -- 难度等级，1-9
 */
void GraphicsScene::initGameAtDifficulty(int difficulty)
{
    for (int i = 0; i < difficulty + 1; ++i) {
        int n = QRandomGenerator::global()->bounded(10);     //随机生成一个必空位置，防止极端概率下满行的情况
        for (int j = 0; j < 10; ++j) {
            if (j == n) {
                continue;
            }
            int w = QRandomGenerator::global()->bounded(1, 100);
            if (w < 55) {
                Block *block = new Block(Qt::darkGray, PassModeBlock);
                this->addItem(block);
                block->moveToAxis(j, i);
            }
        }
    }
}

/**
 * @brief   设置难度
 * @details 如果开启速度增加，则根据难度增加对应速度
 */
void GraphicsScene::set_pass_difficulty(int newPass_difficulty)
{
    if (newPass_difficulty > 9) {
        newPass_difficulty = 9;
    }
    m_pass_difficulty = newPass_difficulty;
    initGameAtDifficulty(m_pass_difficulty);
    if (ST->settings()->value("SpeedOn", true).toBool()) {
        speed_item->setPlainText(QString::number(newPass_difficulty));
        currentBlockGroup->setSpeed(newPass_difficulty);
    }
    pass_item->setPlainText(tr("关卡%1").arg(m_pass_difficulty));
}

void GraphicsScene::fresh_time_on_record()
{
    auto current = pass_time_text_current_list[m_pass_difficulty-1];
    auto record = pass_time_record_list[m_pass_difficulty - 1];
    QString sec;
    if (record.isNull()) {
        current->setDefaultTextColor(Qt::green);
        sec = "";
    } else if (game_time < record) {
        current->setDefaultTextColor(Qt::green);
        sec = QString("(-%1)").arg(game_time.msecsTo(record) / 1000.0);
    } else if (game_time == record) {
        current->setDefaultTextColor(Qt::white);
        sec = "(-0)";
    } else {
        current->setDefaultTextColor(Qt::red);
        sec = QString("(+%1)").arg(record.msecsTo(game_time) / 1000.0);
    }
    // current->setPlainText(game_time.toString("hh:mm:ss") +sec);
    auto font = current->font();
    font.setBold(true);
    current->setFont(font);
    current->setPlainText(game_time.toString("mm:ss.z") +sec);
}
